import { fetch } from 'dva';
import { Common, HttpResponse, Md5 } from 'UtilsCommon';
import { EnvConfig } from 'Configs';

export function get(url, resKey, serviceName, headers) {
    return fetchRequest(url, null, resKey, serviceName, headers);
}

export function post(url, data, resKey, serviceName, headers) {
    return fetchByMethod(url, data, resKey, serviceName, headers, "POST");
}

export function put(url, data, resKey, serviceName, headers) {
    return fetchByMethod(url, data, resKey, serviceName, headers, "PUT");
}

export function delete2(url, data, resKey, serviceName, headers) {
    return fetchByMethod(url, data, resKey, serviceName, headers, "DELETE");
}

export function postFormData(url, data, resKey, serviceName, headers) {
    return fetchRequest(url, {
        method: "POST",
        headers: {},
        body: getFormData(data),
    }, resKey, serviceName, headers);
}

function getFormData(data) {
    if (!data || data instanceof FormData) return data;

    const formData = new FormData();
    for (const key in data) formData.append(key, data[key]);
    return formData;
}

export function fetchByMethod(url, data, resKey, serviceName, headers, method) {
    return fetchRequest(url, {
        method: method || "POST",
        headers: { "Content-type": "application/json; charset=utf-8" },
        body: JSON.stringify(data)
    }, resKey, serviceName, headers);
}

async function fetchRequest(url, data, resKey, serviceName, headers) {
    try {
        data = setParamsHeader(data, headers);
        data = await setServiceHeader(data, serviceName);
        url = getFullUrl(url);
        return fetch(url, data).then(res => setResult(res)).then(d => HttpResponse.getResponse(d, resKey), res => HttpResponse.getErrorResponse(res));
    }
    catch (error) {
        console.warn("dva-common/utils/request/fetchRequest", error);
        const res = { isSuccess: false, message: error.message || error };
        return HttpResponse.getErrorResponse(res, url, data);
    }
}

function setParamsHeader(data, headers) {
    data = data || {};
    data.headers = data.headers || {};

    if (headers) {
        for (const key in headers) data.headers[key] = headers[key];
    }

    return data;
}

async function setServiceHeader(data, serviceName) {
    if (!serviceName) return data;

    if (serviceName === 'WebService' || serviceName === 'A2ApiService') return data;

    const time = await getCurrentTime();

    if (data.headers.isAppToken) data.headers.token = EnvConfig.token;
    else {
        data.headers.token = Common.getStorage(EnvConfig.tokenKey);
        if (!data.headers.token || data.headers.isNoToken) data.headers.token = `oerjgoejrgojgo4jgioj4gon41on3o4n${window.btoa(Common.createGuid())}`;
    }
    data.headers['access-token'] = getAccessToken(data.headers.token, time);
    if (window.appId) data.headers.dappid = window.btoa(window.appId);

    if (data.headers.hasOwnProperty('isNoToken')) delete data.headers.isNoToken;
    if (data.headers.hasOwnProperty('isAppToken')) delete data.headers.isAppToken;

    return setApiServiceHeader(data, serviceName);
}

function setApiServiceHeader(data, serviceName) {
    data = data || { headers: {}, method: "GET" };

    return data;
}

function getCurrentTime() {
    const url = `${EnvConfig.getServiceUrl('ApiService')()}Default/GetCurrentTime`;

    if (window.timeDiff) return Promise.resolve(new Date().getTime() + window.timeDiff);

    const startTime = new Date().getTime();
    return get(url).then(res => {
        if (res.Time) {
            window.timeDiff = res.Time - startTime;
            return Promise.resolve(res.Time);
        }
        return Promise.resolve(new Date().getTime());
    });
}

function getAccessToken(token, time) {
    const appId = EnvConfig.appId;
    const md5str = Md5(appId + time + token);
    return window.btoa(`${appId}@${time}@${md5str}`);
}

function getFullUrl(url) {
    return Common.addUrlRandom(url);
}

function setResult(res) {
    return res.ok && res.status === 200 ? res.json() : Promise.reject(`${res.status}:${Common.isNullOrEmptyReturnDefault(res.statusText, "请求错误！")}`);
}